<?php

namespace app\extensions;

use inhere\librarys\collections\DataCollector;
use inhere\librarys\files\File;
use Slim;
use inhere\librarys\StdBase;
use inhere\librarys\helpers\ObjectHelper;

/**
 * Class MdpManager
 * @package app\extensions
 */
class MdpManager extends StdBase
{
    /**
     * 最多允许多少个项目
     * @var int
     */
    protected $maxProject = 50;

    /**
     * @var string
     */
    protected $configPath = '@project/config/projects';

    /**
     * @var string
     */
    protected $cacheFile = '@project/resources/data/raw/projects.json';

    /**
     * @var array|mixed
     */
    protected $sources = [
        'path'        => '@project/sources',
         # false delete, will move file to trashPath
        'falseDelete' => true,
         # detection change of the data file
        'detectChange' => true,
        'trashPath'   => '@project/temp/trash',
        'suffix'      => '.md',
    ];

    /**
     * @var array|mixed
     */
    protected $outputs = [
        'path' => "@temp/outputs",
        # compress content when write to output file
        'compress' => false,
        'suffix' => ".html",
    ];

    /**
     * [
     *   'domain' => 'project name',   
     *   'domain1' => 'project name1',   
     * ]
     * @var array
     */
    private $domainMap = [];

    /**
     * @var array
     */
    private $names = [];

    /**
     * @var array
     */
    private $projects = [];

    /**
     * @param array $options
     */
    public function __construct(array $options = [])
    {
        ObjectHelper::loadAttrs($this, $options);
    }

    /**
     * @param bool|false $refresh
     * @return $this
     */
    public function loadConfig($refresh = false)
    {
        if ( !$refresh && $this->loadConfigFromCache() ) {
            return $this;
        }

        $this->loadConfigFromFiles()->cacheConfigToFile();

        return $this;
    }

    /**
     * @return $this
     */
    protected function loadConfigFromFiles()
    {
        $index = 0;
        $path = $this->getConfigPath();
        $files = glob($path . '/*.yml');

        foreach ($files as $file) {
            if ($index === $this->maxProject) {
                break;
            }

            $name = basename($file,'.yml');

            if ( !preg_match('/^[a-zA-Z][a-zA-Z-_0-9]+/i', $name) ) {
                continue;
            }

            $str = File::getContents($file);
            $this->names[] = $name;
            $this->projects[$name] = DataCollector::parseYaml(trim($str));

            // have config domain
            if ( isset($this->projects[$name]) && ($domain = $this->projects[$name]['domain']) ) {
                $this->domainMap[$domain] = $name;
            }

            $index++;
        }

        return $this;
    }

    /**
     * @return bool
     */
    protected function loadConfigFromCache()
    {
        $cacheFile = $this->getCacheFile();

        if ( !is_file($cacheFile) || !is_readable($cacheFile)) {
            return false;
        }

        if ($str = file_get_contents($cacheFile) ) {

            $this->projects = json_decode($str, true);

            // 空的文件 || 解析json文件失败
            if (!$this->projects || JSON_ERROR_NONE !== json_last_error()) {
                return false;
            }

            $this->names = array_keys($this->projects);

            return true;
        }

        return false;
    }

    /**
     * @return bool
     */
    protected function cacheConfigToFile()
    {
        if (!$this->projects) {
            return false;
        }

        $str = json_encode($this->projects);
        $cacheFile = $this->getCacheFile();
        $path = dirname($cacheFile);

        if (!is_dir($path)) {
            mkdir($path, 0775, true);
        }

        if ( false === file_put_contents($cacheFile, $str) ) {
            throw new \RuntimeException('写入文件内容失败！FILE: ' . $cacheFile);
        }

        return true;
    }

    /**
     * @param $name
     * @return bool
     */
    public function hasProject($name)
    {
        return in_array($name, $this->names);
    }

    /**
     * @param $name
     * @return array
     */
    public function getProject($name)
    {
        if ( $this->hasProject($name) ) {
            return [];
        }

        return $this->projects[$name];
    }


    /**
     * @param $name
     * @return MdProject|null
     */
    public function findProject($name)
    {
        if ( !$this->hasProject($name) ) {
            return null;
        }

        $config = $this->projects[$name];

        return new MdProject($name, $config);
    }

    public function getCanAccessProjects()
    {
        $projects = [];

        foreach ($this->projects as $p) {
            $bl = !empty($p['belongTo']) ? $p['belongTo'] : [];
            
        }
    }

    /**
     * @return bool|string
     */
    public function getConfigPath()
    {
        return Slim::alias($this->configPath);
    }

    /**
     * @param $path
     */
    public function setConfigPath($path)
    {
        if ( $path = trim($path) ) {
            $path = Slim::alias($path);

            if (!file_exists($path)) {
                throw new \RuntimeException('项目配置路径不存在。PATH: ' . $path);
            }

            $this->configPath = $path;
        }
    }

    /**
     * @return bool|string
     */
    public function getCacheFile()
    {
        return Slim::alias($this->cacheFile);
    }

    /**
     * @param $file
     */
    public function setCacheFile($file)
    {
        if ( $file = trim($file) ) {
            $this->cacheFile = $file;
        }
    }

    /**
     * @param $key
     * @param mixed $default
     * @return mixed
     */
    public function getSource($key, $default=null)
    {
        return isset($this->sources[$key]) ? $this->sources[$key] : $default;
    }


    /**
     * @return bool|string
     */
    public function getSourcePath()
    {
        return ($path=$this->getSource('path')) ? Slim::alias($path) : '';
    }

    /**
     * @return bool|string
     */
    public function getTrashPath()
    {
        return ($path=$this->getSource('trashPath')) ? Slim::alias($path) : '';
    }

    /**
     * @return bool|string
     */
    public function getOutputPath()
    {
        return ($path=$this->getOutput('path')) ? Slim::alias($path) : '';
    }

    /**
     * @param $key
     * @param mixed $default
     * @return mixed
     */
    public function getOutput($key, $default=null)
    {
        return isset($this->outputs[$key]) ? $this->outputs[$key] : $default;
    }

    /**
     * @return array|mixed
     */
    public function getSources()
    {
        return $this->sources;
    }

    /**
     * @param array $data
     */
    public function setSources(array $data)
    {
        $this->sources = array_merge($this->sources, $data);
    }

    /**
     * @param array $data
     */
    public function setOutputs(array $data)
    {
        $this->outputs = array_merge($this->outputs, $data);
    }
}
